<template>
  <div class="view-tabs">
    <el-tabs
      type="border-card"
      v-model="curTabKey"
      closable
      @tab-click="clickTab"
      @tab-remove="removeTab"
    >
      <el-tab-pane
        v-for="item in tabs"
        :label="item.title"
        :name="item.tabKey"
        :key="item.tabKey"
      >
        <template slot="label">
          {{ item.title }}
          <i
            v-if="curTabKey === item.tabKey"
            class="el-icon-refresh"
            @click="refreshTab(item)"
          ></i>
        </template>
      </el-tab-pane>
    </el-tabs>
    <i class="el-icon-circle-close close-tabs" @click="closeOtherTabs"></i>
  </div>
</template>

<script>
import { mapMutations, mapActions } from 'vuex';
import EventBus from '@/eventBus';
export default {
  name: 'ViewTabs',
  props: {
    // 【根据项目修改】tab页面在路由的第几层，或者说第几层的 router-view 组件（当前项目为第二层）
    tabRouteViewDepth: {
      type: Number,
      default: 2,
    },
    // tab页面的key值，从route对象中取，一个key值对应一个tab页面
    // 默认为matchRoute.path值
    getTabKey: {
      type: Function,
      default: function (routeMatch /* , route */) {
        return routeMatch.path;
      },
    },
    // tab页签的标题，默认从路由meta.title中获取
    tabTitleKey: {
      type: String,
      default: 'title',
    },
  },
  data() {
    return {
      tabs: [],
      curTabKey: '',
    };
  },
  methods: {
    ...mapActions('cache', ['addCache', 'removeCache', 'removeCacheEntry']),
    ...mapMutations(['setIsRenderTab']),
    // 切换tab
    changeCurTab() {
      // 当前路由信息
      const { path, query, params, hash, matched } = this.$route;
      // tab标签页路由信息：meta、componentName
      const routeMatch = matched[this.tabRouteViewDepth - 1];
      const meta = routeMatch.meta;
      const componentName = routeMatch.components?.default?.name;
      // 获取tab标签页信息：tabKey标签页key值；title-标签页标题；tab-存在的标签页
      const tabKey = this.getTabKey(routeMatch, this.$route);
      const title = String(meta[this.tabTitleKey] || '');
      const tab = this.tabs.find((tab) => tab.tabKey === tabKey);

      if (!tabKey) {
        // tabKey默认为路由的name值
        console.warn(
          `LayoutTabs组件：${path} 路由没有匹配的tab标签页，如有需要请配置tab标签页的key值`,
        );
        return;
      }

      // 如果同一tab路径变了（例如路径为 /detail/:id），则清除缓存实例
      if (tab && tab.path !== path) {
        this.removeCacheEntry(componentName || '');
        tab.title = '';
      }

      const newTab = {
        tabKey,
        title: tab?.title || title,
        path,
        params,
        query,
        hash,
        componentName,
      };
      tab ? Object.assign(tab, newTab) : this.tabs.push(newTab);
      this.curTabKey = tabKey;
    },
    // 点击tab
    clickTab(pane) {
      if (!pane.index) return;

      const tab = this.tabs[Number(pane.index)];
      if (tab.path !== this.$route.path) {
        this.gotoTab(tab);
      }
    },
    // 移除tab
    async removeTab(tabKey) {
      // 剩下一个时不能删
      if (this.tabs.length === 1) return;

      const index = this.tabs.findIndex((tab) => tab.tabKey === tabKey);
      if (index < -1) return;

      const tab = this.tabs[index];
      this.tabs.splice(index, 1);

      // 如果删除的是当前tab，则切换到最后一个tab
      if (tab.tabKey === this.curTabKey) {
        const lastTab = this.tabs[this.tabs.length - 1];
        lastTab && this.gotoTab(lastTab);
      }
      this.removeCache(tab.componentName || '');
    },
    // 跳转tab页面
    async gotoTab(tab) {
      await this.$router.push({
        path: tab.path,
        query: tab.query,
        hash: tab.hash,
      });
    },
    // 关闭非当前页的所有tab页签
    closeOtherTabs() {
      this.tabs
        .filter((tab) => tab.tabKey !== this.curTabKey)
        .forEach((tab) => {
          this.removeCache(tab.componentName || '');
        });
      this.tabs = this.tabs.filter((tab) => tab.tabKey === this.curTabKey);
    },
    // 刷新当前tab页面
    async refreshTab(tab) {
      this.setIsRenderTab(false);
      await this.removeCacheEntry(tab.componentName);
      this.setIsRenderTab(true);
    },
    // 关闭tab页面，默认关闭当前页
    async closeLayoutTab(tabKey = this.curTabKey) {
      const index = this.tabs.findIndex((tab) => tab.tabKey === tabKey);
      if (index > -1) {
        this.removeCache(this.tabs[index].componentName);
        this.tabs.splice(index, 1);
      }
    },
    // 设置当前tab的标题
    setCurTabTitle(title) {
      const curTab = this.tabs.find((tab) => tab.tabKey === this.curTabKey);
      if (curTab) {
        curTab.title = title;
      }
    },
  },
  watch: {
    '$route.path': {
      handler() {
        this.changeCurTab();
      },
      immediate: true,
    },
  },
  created() {
    // 对外提供的事件：关闭弹窗；设置tab标题
    EventBus.$on('LayoutTabs:closeTab', (tabKey) => {
      this.closeLayoutTab(tabKey);
    });
    EventBus.$on('LayoutTabs:setTabTitle', (title) => {
      this.setCurTabTitle(title);
    });
  },
};
</script>
<style scoped>
.view-tabs {
  overflow-y: hidden;
  overflow-x: auto;
  position: relative;
}
.view-tabs >>> .el-tabs__item {
  /* // background-color: #175cd2; */
  /* // width: 120px; */
  height: 30px;
  /* line-height: 47px; */
  text-align: center;
  font-size: 14px;
  line-height: 30px;
  /* font-weight: bold; */
  color: white;
  padding: 0 10px;
}
.view-tabs >>> .el-tabs--border-card {
  border: 0px;
  box-shadow: none;
  background: none;
}

.view-tabs >>> .el-tabs--border-card > .el-tabs__header {
  background-color: white;
}

/* .view-tabs >>> .el-tabs__nav-scroll {
  background-color: #eceef3;
} */
.view-tabs >>> .el-tabs__nav-scroll {
  background-color: #eceef3;
  overflow-x: auto;
}

.view-tabs >>> .el-tabs--border-card > .el-tabs__header .el-tabs__nav {
  border: none;
}

.view-tabs >>> .el-tabs--border-card > .el-tabs__header .el-tabs__item {
  background-color: rgba(255, 255, 255, 100);
  color: #606266;
  border: 1px solid #dcdfe6;
  margin-bottom: 5px;
  margin-top: 5px;
  margin-left: 5px;
  border-radius: 25px;
  padding-right: 10px;
}
.view-tabs
  >>> .el-tabs--border-card
  > .el-tabs__header
  .el-tabs__item.is-active {
  background-color: #67c23a;
  color: #fff;
  border: 1px solid #67c23a;
}

.view-tabs >>> .el-tabs--border-card > .el-tabs__content {
  padding: 0px;
}

.close-tabs {
  position: absolute;
  top: -2px;
  right: 0;
  padding: 12px;
  cursor: pointer;
  font-size: 1.5em;
  color: #606266;
}
</style>
